﻿// main.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#define BT_USE_DOUBLE_PRECISION
#include <osgViewer/viewer>
#include <osgEarth/Notify>
#include <osgEarth/EarthManipulator>
#include <osgEarth/MapNode>
#include <osgEarth/Threading>
#include <osgEarth/ShaderGenerator>
#include <osgDB/ReadFile>
#include <osgGA/TrackballManipulator>
#include <osgUtil/Optimizer>
#include <iostream>
#include <osgEarth/Metrics>
#include "osgEarth/GDAL";
#include <osgEarth/TMS>
#include <osgEarth/Terrain>
#include <osg/TriangleFunctor>
#include <osg/ShapeDrawable>
#include <TileNode>

using namespace osgEarth;
using namespace osgEarth::Util;
#include <iostream>
#include <unordered_map>
#include <mutex>
using namespace std;
//SKY
#include "osgEarthDrivers\sky_simple\SimpleSkyNode"//for the sky
#include "osgEarthDrivers\sky_simple\SimpleSkyOptions"//for the sky
//bullet
#include "btBulletCollisionCommon.h"
#include "btBulletDynamicsCommon.h"
//IMGUI
#include "imgui.h"
#include "imgui_impl_opengl3.h"
#include "OsgImGuiHandler.hpp"

#include <osgEarth/MouseCoordsTool>

osgEarth::MapNode* g_mapNode = 0;
osg::Group* g_root = 0;
btDiscreteDynamicsWorld* g_dynamicsWorld = 0;

//把与一个地形瓦片相关的osg指针和bullet指针放在一起管理
struct OsgAndBtTileInfo {
	btRigidBody* _btBody=0;
	btBvhTriangleMeshShape* _btShape=0;
	btTriangleMesh* _btVerts=0;
	osg::ref_ptr<osg::Geode> _geode;
};

std::unordered_map<string, OsgAndBtTileInfo> g_physicsTileNodeContainer ;

vector<osg::Node*> g_movingBoxArr;
vector<osg::Node*> g_prepareToAddArr;
osgViewer::Viewer* g_viewer = 0;

std::mutex g_physicsTerrainGeodeMutex;
vector<osg::ref_ptr<osg::Node> > g_physicsTerrainGeodeInsertArr;
vector<osg::ref_ptr<osg::Node> > g_physicsTerrainGeodeRemoveArr;

struct MyBtBody :public osg::Referenced
{
public:
	MyBtBody(btRigidBody* body) { _body = body; }
	~MyBtBody() {
		cout << "debug ~MyBtBody" << endl;
		if(_body) delete _body; _body = 0;
	}
	btRigidBody* getBtBody() { return _body; }
protected:
	btRigidBody* _body;
};

struct MyMouseCallback :public osgEarth::Contrib::MouseCoordsTool::Callback
{
	virtual void set(const GeoPoint& coords, osg::View* view, MapNode* mapNode);
	virtual void reset(osg::View* view, MapNode* mapNode);
	virtual void handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa);
	bool _rightPushed = false;
};
void MyMouseCallback::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
	if (ea.getEventType() == osgGA::GUIEventAdapter::EventType::PUSH
	   && ea.getButton()==4 ) {
		if(_rightPushed==false)_rightPushed = true;
	}

}
void MyMouseCallback::set(const GeoPoint& coords, osg::View* view, MapNode* mapNode) {
	
	
	//if (g_debugMouseAltitude == true) {
	//	//cout << "debug mouse alt" << endl; 
	//	osgEarth::GeoPoint gp(osgEarth::SpatialReference::get("wgs84"), 116.1639, 40.2501, 0, osgEarth::AltitudeMode::ALTMODE_ABSOLUTE);
	//	osgEarth::GeoPoint gp2(osgEarth::SpatialReference::get("wgs84"), 116.1639, 40.2501, 0, osgEarth::AltitudeMode::ALTMODE_RELATIVE);
	//	bool ok1 = gp.makeAbsolute(g_mapNode->getTerrain());
	//	bool ok2 = gp2.makeAbsolute(g_mapNode->getTerrain());
	//	//cout << "debug ok1 ok2 " << ok1 << " " << ok2 << endl;
	//	g_debugMouseAltitude = false;
	//}

	//GeoPoint& coords 是经纬度和海拔高度坐标
	if (_rightPushed) {
		osg::Vec3d worldCoords;
		coords.toWorld(worldCoords);//经纬度转为笛卡尔坐标
		stringstream ss;
		ss << "Lon:" << coords.x() << ",Lat:" << coords.y() << ",Alt:" << coords.alt();
		cout << ss.str() << endl;
		cout << "x y z " << worldCoords.x() << " " << worldCoords.y() << " " << worldCoords.z() << endl;
		_rightPushed = false;
	}
	
	//osg::Vec3d eye, center, up;
	//view->getCamera()->getViewMatrixAsLookAt(eye, center, up);
	//cout << "x y z " << eye.x() << " " << eye.y() << " " << eye.z() << endl;
	//g_myMouseCallbackText = ss.str();
}
void MyMouseCallback::reset(osg::View* view, MapNode* mapNode) {
}
MyMouseCallback* g_mousecallback = 0;

osg::Node* createOsgBodyBox(osg::Vec3d& startPos, osg::Vec3d& dir, double boxWid);
class MyMouseCallback2 : public osgGA::GUIEventHandler
{
public:
	bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) override;
};
bool MyMouseCallback2::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) 
{
	if (ea.getEventType() == osgGA::GUIEventAdapter::EventType::RELEASE ) {
		//ea.getButton() 1 Left button
		//ea.getButton() 3 Mid button
		//ea.getButton() 4 Right button
		if (ea.getButton()==4) {
			osg::View* view = aa.asView();
			float mx = ea.getX();
			float my = ea.getY();
			osg::Vec3d eye, tar, up;
			view->getCamera()->getViewMatrixAsLookAt(eye, tar, up, 100.0);
			//left,right,top,bottom are all in near plane.
			double projLeft(0), projRight(0), projTop(0), projBottom(0), projNear(0), projFar(0);
			view->getCamera()->getProjectionMatrixAsFrustum(projLeft, projRight, projBottom, projTop, projNear, projFar);
			osg::Matrixd invViewMat = view->getCamera()->getInverseViewMatrix();

			//计算鼠标点在近平面的View坐标
			int winWidth = view->getCamera()->getViewport()->width();
			int winHeight = view->getCamera()->getViewport()->height();
			double mouse_vx = (mx / winWidth - 0.5) * (projRight - projLeft);
			double mouse_vy = (my / winHeight - 0.5) * (projTop - projBottom);
			double mouse_vz = -projNear;

			// !这里矢量需要进行矩阵变换的话，需要把矢量放在前面乘以矩阵，我试过了矢量放在后面不行的。
			//计算鼠标点在近平面的世界坐标
			osg::Vec4d mouse_world = osg::Vec4d(mouse_vx, mouse_vy, mouse_vz, 1) * invViewMat  ;

			//计算从摄像机到鼠标点的方向矢量，矢量箭头指向鼠标点。
			osg::Vec3d shootDirection = osg::Vec3d(mouse_world.x(), mouse_world.y(),mouse_world.z()) - eye;
			
			shootDirection.normalize();
			osg::Node* nodePtr = createOsgBodyBox(eye, shootDirection, 10);
			g_prepareToAddArr.push_back(nodePtr);
			g_movingBoxArr.push_back(nodePtr);
			//cout << "debug fire" << endl;
		}
	}
	return false;
}


btVector3 osg2bt(osg::Vec3d& v) {
	return btVector3(v.x(), v.y(), v.z());
}

// CollectTriangles from osgearth_createtile.cpp
struct CollectTriangles
{
	CollectTriangles()
	{
		verts = new osg::Vec3Array();
	}
	inline void operator () (const osg::Vec3& v1, const osg::Vec3& v2, const osg::Vec3& v3)
	{
		verts->push_back(v1);
		verts->push_back(v2);
		verts->push_back(v3);
	}
	osg::ref_ptr< osg::Vec3Array > verts;
};
// CollectTrianglesVisitor from osgearth_createtile.cpp
struct CollectTrianglesVisitor : public osg::NodeVisitor
{
	CollectTrianglesVisitor() :
		osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
	{
		_vertices = new osg::Vec3dArray();
		//_verticesLocal = new osg::Vec3dArray();
		_ndrawable = 0;
	}
	void apply(osg::Transform& transform)
	{
		osg::Matrix matrix;
		if (!_matrixStack.empty()) matrix = _matrixStack.back();
		transform.computeLocalToWorldMatrix(matrix, this);
		pushMatrix(matrix);
		traverse(transform);
		popMatrix();
	}
	void apply(osg::Drawable& drawable) override
	{
		if (_ndrawable > 0) return;//skip, we need only one tile.
		++_ndrawable;
		osg::TriangleFunctor<CollectTriangles> triangleCollector;
		drawable.accept(triangleCollector);
		for (unsigned int j = 0; j < triangleCollector.verts->size(); j++)
		{
			static osg::Matrix identity;
			osg::Matrix& matrix = _matrixStack.empty() ? identity : _matrixStack.back();
			osg::Vec3d v = (*triangleCollector.verts)[j];
			_vertices->push_back(v * matrix);
			//_verticesLocal->push_back(v);
		}
	}
	inline void pushMatrix(osg::Matrix& matrix) { _matrixStack.push_back(matrix); }
	inline void popMatrix() { _matrixStack.pop_back(); }
	typedef std::vector<osg::Matrix> MatrixStack;
	osg::ref_ptr<osg::Vec3dArray>  _vertices;
	//osg::ref_ptr<osg::Vec3dArray> _verticesLocal;
	MatrixStack _matrixStack;
	int _ndrawable;
};

struct OsgBodyBoxUpdateCallback : public osg::NodeCallback
{ 
public:
	virtual void operator() (osg::Node* node, osg::NodeVisitor* nv);
};
void OsgBodyBoxUpdateCallback::operator() (osg::Node* node, osg::NodeVisitor* nv)
{
	osg::MatrixTransform* mt1 = static_cast<osg::MatrixTransform*>(node);
	if (mt1) {
		MyBtBody* mybody = (MyBtBody*)mt1->getUserData();
		//更新box位置
		btTransform trans1 = mybody->getBtBody()->getWorldTransform();
		double matrixdata[16];
		trans1.getOpenGLMatrix(matrixdata);
		double bx = trans1.getOrigin().x();
		double by = trans1.getOrigin().y();
		double bz = trans1.getOrigin().z();
		//cout << bx << " " << by << " " << bz << endl;
		mt1->setMatrix(osg::Matrix(matrixdata));
		//gravity
		btVector3 ggg(bx, by, bz);
		ggg = ggg.normalize() * -10;
		mybody->getBtBody()->setGravity(ggg);
	}
	traverse(node, nv);
}

osg::Node* createOsgBodyBox(osg::Vec3d& startPos, osg::Vec3d& dir, double boxWid ) {
	double startx = startPos.x();
	double starty = startPos.y();
	double startz = startPos.z();
	double boxwidth = boxWid;

	btBoxShape* shp = new btBoxShape(btVector3(boxwidth / 2, boxwidth / 2, boxwidth / 2));
	btTransform startTransform;
	startTransform.setIdentity();
	startTransform.setOrigin(btVector3(startx, starty, startz));
	btVector3 localInertia(0, 0, 0);
	btScalar mass(boxWid*boxWid*boxWid);
	shp->calculateLocalInertia(mass, localInertia);
	btDefaultMotionState* ms = new btDefaultMotionState(startTransform);
	btRigidBody* body = new btRigidBody(btRigidBody::btRigidBodyConstructionInfo(
		mass, ms, shp, localInertia));
	body->setRestitution(0.9);
	body->setFlags(BT_ENABLE_GYROSCOPIC_FORCE_EXPLICIT|BT_ENABLE_GYROSCOPIC_FORCE_IMPLICIT_WORLD|BT_ENABLE_GYROPSCOPIC_FORCE);
	//初始速度 500m/s
	btVector3 initVel = osg2bt(dir)*500;
	body->setLinearVelocity(initVel);
	g_dynamicsWorld->addRigidBody(body);

	osg::ShapeDrawable* draw1 = new osg::ShapeDrawable(new osg::Box(osg::Vec3d(0, 0, 0), boxwidth));
	draw1->setColor(osg::Vec4(1, 0, 0, 1));
	osg::Geode* geode1 = new osg::Geode;
	geode1->addDrawable(draw1);
	osg::MatrixTransform* mt1 = new osg::MatrixTransform;
	mt1->setMatrix(osg::Matrix::translate(osg::Vec3d(startx, starty, startz)));//6372000
	mt1->addUpdateCallback(new OsgBodyBoxUpdateCallback);
	mt1->setUserData(new MyBtBody(body));
	mt1->addChild(geode1);
	return mt1;
}


//初始化IMGUI
class ImGuiInitOperation : public osg::Operation
{
public:
	ImGuiInitOperation()
		: osg::Operation("ImGuiInitOperation", false){}
	void operator()(osg::Object* object) override
	{
		osg::GraphicsContext* context = dynamic_cast<osg::GraphicsContext*>(object);
		if (!context)return;
		if (!ImGui_ImplOpenGL3_Init()){std::cout << "ImGui_ImplOpenGL3_Init() failed\n";}
	}
};
//IMGUI控件绘制类
class MyIMGuiHandler : public OsgImGuiHandler
{
public:
	MyIMGuiHandler() {}
protected:
	void drawUi() override //绘制控件
	{
		// ImGui code goes here...
		ImGui::Begin("Tut-33 osgEarth with bullet");
		//ImGui::Text("Some text");
		ImGui::Spacing();
		if (ImGui::Button("Fire"))
		{
			osg::Vec3d eye, center, up;
			g_viewer->getCamera()->getViewMatrixAsLookAt(eye, center, up, 1000);
			//cout << "x y z " << eye.x() << " " << eye.y() << " " << eye.z() << endl;
			osg::Vec3d shootDir = center - eye;
			shootDir.normalize() ;
			osg::Node* nodePtr = createOsgBodyBox(center, shootDir, 10);
			g_prepareToAddArr.push_back(nodePtr);
			g_movingBoxArr.push_back(nodePtr);
		}
		ImGui::End();
	}
private:
	float _sliderValue = 0;
};
//Terrain callback
class MyTerrainCallback : public osgEarth::TerrainCallback
{
public:
	virtual void 	onTileUpdate(const TileKey& key, osg::Node* graph, TerrainCallbackContext& context);
	virtual inline ~MyTerrainCallback() { cout << "deallocate MyTerrainCallback." << endl;  };
	virtual void 	onTileAdded(const TileKey& key, osg::Node* graph, TerrainCallbackContext& context);
};
void MyTerrainCallback::onTileUpdate(const TileKey& key, osg::Node* graph, TerrainCallbackContext& context)
{
	//cout << key.getLOD() << endl;
	if (key.getLOD() == 15 ) 
	{
		auto lastBody = g_physicsTileNodeContainer.find(key.str());
		if (lastBody  != g_physicsTileNodeContainer.end()) {
			cout << "debug find repeat body and remove for key " << key.str() << endl;
			g_dynamicsWorld->removeRigidBody(lastBody->second._btBody);
			delete lastBody->second._btBody;
			delete lastBody->second._btShape;
			delete lastBody->second._btVerts;
			g_physicsTerrainGeodeRemoveArr.push_back(lastBody->second._geode);
			g_physicsTileNodeContainer.erase(lastBody);
		}

		// the max lod of DEM
		//"https://readymap.org/readymap/tiles/1.0.0/116/10" units-per-pixel="0.00068397373540856027
		CollectTrianglesVisitor v;
		graph->accept(v);
		if (v._vertices->size() > 0 ) {
			//osg::Vec3d v0 = v._vertices->at(0);//这个是地心坐标。 -6341734 , 0.0 , 620421 单位米
			//osg::Vec3d v1 = v._verticesLocal->at(0);// 这个是相对瓦片矩阵的相对坐标，-4484283， -2710778 -2757882
			//cout << "MyTerrainCallback::onTileUpdate " << key.str() << " " << v._vertices->size() << endl;

			//physics
			g_physicsTerrainGeodeMutex.lock();

			OsgAndBtTileInfo osgbtTileInfo;
			int numTri = v._vertices->size() / 3;
			osgbtTileInfo._btVerts = new btTriangleMesh;
			osg::Vec3dArray* vertArr = new osg::Vec3dArray;// 这个用于绘制物理表面的线网格，内存归geode负责释放
			for (size_t itri = 0; itri < numTri; ++itri)
			{
				osgbtTileInfo._btVerts->addTriangle(osg2bt(v._vertices->at(itri * 3 + 0))
					, osg2bt(v._vertices->at(itri * 3 + 1))
					, osg2bt(v._vertices->at(itri * 3 + 2)));		
				vertArr->push_back(v._vertices->at(itri * 3 + 1));
				vertArr->push_back(v._vertices->at(itri * 3 + 2));
			}
			//bt staff
			osgbtTileInfo._btShape = new btBvhTriangleMeshShape( osgbtTileInfo._btVerts , false, true);
			btTransform btTrans;
			btTrans.setIdentity();
			btTrans.setOrigin(btVector3(0, 0, 0));
			osgbtTileInfo._btBody = new btRigidBody(btScalar(0), 0, osgbtTileInfo._btShape);
			g_dynamicsWorld->addRigidBody(osgbtTileInfo._btBody);

			//osg staff
			osg::Geometry* geom = new osg::Geometry();
			geom->setVertexArray(vertArr);//hand over vertArr to geom.
			osg::Vec4dArray* colorArr = new osg::Vec4dArray;
			colorArr->push_back(osg::Vec4d(0.5,0.5,0.5,0.5));
			geom->setColorArray(colorArr, osg::Array::Binding::BIND_OVERALL);
			geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, vertArr->size()));
			osgbtTileInfo._geode = new osg::Geode();
			osgbtTileInfo._geode->addDrawable(geom);

			//add to container
			g_physicsTileNodeContainer[key.str()] = osgbtTileInfo;

			
			g_physicsTerrainGeodeInsertArr.push_back(osgbtTileInfo._geode);
			g_physicsTerrainGeodeMutex.unlock();


			//if (g_terrainMeshBodyContainer.find( key.str() )!= g_terrainMeshBodyContainer.end() ) {
			//	cout << "debug repeat tile " << key.str() << endl;

			//}
			//else {
			//	g_terrainMeshBodyContainer[key.str()] = rigidbody;
			//	g_dynamicsWorld->addRigidBody(rigidbody);
			//	//cout << "debug physics num " << g_dynamicsWorld->getNumCollisionObjects() << endl;
			//}

			
			//cout << "debug physics num " << g_dynamicsWorld->getNumCollisionObjects() << endl;
		}
	}
	
	
	// 这里每个瓦片的顶点数有几种情况，1536是17x17个点组成的三角网格，这个是正常的瓦片。
	// 然后还有几种情况不清楚怎么算的：6144 10752 15360 19968 29184 33792 208896 
	// 这个visitor返回的点数量都是1536的整数倍，经过检查，发现是它会把瓦片的子瓦片的点都压入栈了。
	// 我们为了使用物理引擎，需要避免这点，找到第一个drawable统计完点就返回，不计入子瓦片的点。
}

void MyTerrainCallback::onTileAdded(const TileKey& key, osg::Node* graph, TerrainCallbackContext& context)
{
	cout << "MyTerrainCallback::onTileAdded " << key.str() << endl;
}

MyTerrainCallback* g_myTerrainCallback = 0;

class MyTileNodeVisitor : public osg::NodeVisitor
{
public:
	MyTileNodeVisitor() :osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
	virtual void apply(osg::Group& node);

	unordered_map<string,bool> _tileKeys;
};

class MyMapNodeUpdateCallback :public osg::NodeCallback
{
public:
	virtual void operator() (osg::Node* node, osg::NodeVisitor* nv);
};
void MyMapNodeUpdateCallback::operator() (osg::Node* node, osg::NodeVisitor* nv)
{
	if (g_mapNode != 0) {
		if (g_mapNode->getTerrain()) {
			if (g_myTerrainCallback == 0) {
				cout << "new MyTerrainCallback" << endl;
				MyTerrainCallback* myTerrainCallback = new MyTerrainCallback;
				g_mapNode->getTerrain()->addTerrainCallback(myTerrainCallback);
				g_myTerrainCallback = myTerrainCallback;
			}
		}
		MyTileNodeVisitor tileVisitor;
		g_mapNode->accept(tileVisitor);
		//cout << "debug tilenode count " << tileVisitor._tileKeys.size() << endl;
		vector<string> needRemovedKeys;
		for (auto it = g_physicsTileNodeContainer.begin(); it != g_physicsTileNodeContainer.end(); ++it) {
			if (tileVisitor._tileKeys.find( it->first ) == tileVisitor._tileKeys.end() ) {
				//delete a unloaded one
				needRemovedKeys.push_back(it->first);
				
			}
		}
		for (auto it = needRemovedKeys.begin(); it != needRemovedKeys.end(); ++it) {
			g_physicsTerrainGeodeMutex.lock();
			auto tinfo = g_physicsTileNodeContainer[*it];
			g_dynamicsWorld->removeRigidBody( tinfo._btBody);
			delete tinfo._btBody;
			delete tinfo._btShape;
			delete tinfo._btVerts;
			g_physicsTerrainGeodeRemoveArr.push_back( tinfo._geode);
			g_physicsTileNodeContainer.erase(*it);
			g_physicsTerrainGeodeMutex.unlock();
		}
	}
	traverse(node, nv);
}


void MyTileNodeVisitor::apply(osg::Group& node)
{
	osgEarth::REX::TileNode* tileNode = dynamic_cast<osgEarth::REX::TileNode*>(&node);
	if (tileNode)
	{
		
		if (tileNode->getKey().getLOD() == 15) {
			_tileKeys[tileNode->getKey().str()]=true;
			//tileNode->isDormant();
			//if (!tileNode->isDormant()) {
			//	++tileNodeCount;
			//}
		}
		//cout << "debug found tile Node " << tileNode->getKey().str() << endl;
	}
	traverse(node);
}



// 下一步增加根据鼠标左键射击box，能够调整初速度。然后这个tut就完成了。下一步做小汽车沿着路径行驶并根据汽车动态加载地形物理面。2024/5/2 04:39.
int main()
{
	cout << "version 1" << endl;//2024/4/21
	cout << "version 2 shot many boxes" << endl;//2024/4/21
	cout << "version 2.1 shot ok." << endl;//2024/5/4
	//bullet physics engine
	btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();
	btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);
	btDbvtBroadphase* broadphase = new btDbvtBroadphase();
	btSequentialImpulseConstraintSolver* soler = new btSequentialImpulseConstraintSolver;
	btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, broadphase, soler, collisionConfiguration);
	g_dynamicsWorld = dynamicsWorld;


	osgEarth::initialize();
	//create a viewer
	osgViewer::Viewer viewer;
	viewer.setUpViewInWindow(0, 100, 800, 600);
	// ? why
	viewer.setReleaseContextAtEndOfFrameHint(false);
	//set camera manipulator
	osgGA::TrackballManipulator* mp = new osgGA::TrackballManipulator;
	osgEarth::EarthManipulator* mp2 = new osgEarth::EarthManipulator;
	viewer.setCameraManipulator(mp2);
	osgEarth::Map* map = new osgEarth::Map();
	
	//layer
	TMSImageLayer* layer1 = new TMSImageLayer();
	layer1->setURL(osgEarth::URI("http://readymap.org/readymap/tiles/1.0.0/7/"));
	map->addLayer(layer1);

	//elevation
	TMSElevationLayer* elev = new TMSElevationLayer();
	elev->setURL(osgEarth::URI("http://readymap.org/readymap/tiles/1.0.0/116/"));
	map->addLayer(elev);

	osg::Group* root = new osg::Group;
	g_root = root;
	osg::ref_ptr<osgEarth::MapNode> mapNode = new osgEarth::MapNode(map);
	viewer.setSceneData(root);
	root->addChild(mapNode);
	g_mapNode = mapNode;
	mapNode->addUpdateCallback(new MyMapNodeUpdateCallback);

	if(true){//SKY
		//SkyOptions options;
		osgEarth::SimpleSky::SimpleSkyOptions options;
		options.quality() = SkyOptions::QUALITY_DEFAULT;
		options.ambient() = 0.001;//控制环境光强度
		options.exposure() = 10.f;//控制白天的亮度
		options.atmosphereVisible() = true;//大气层厚度是否可见
		options.atmosphericLighting() = true;//大气散射光是否可见
		options.sunVisible() = true;
		options.moonVisible() = true;
		options.starsVisible() = true;
		options.usePBR() = true;
		//添加天空模型
		//mapNode->addExtension(Extension::create("sky_simple", options));//这里不能使用addChild, Extension是一种更复杂的对象
	}
	
	//IMGUI
	viewer.setRealizeOperation(new ImGuiInitOperation);//imgui
	viewer.addEventHandler(new MyIMGuiHandler);//imgui
	viewer.addEventHandler(new MyMouseCallback2);
	g_viewer = &viewer;



	//Metrics::run(viewer);
	while (!viewer.done()) {

		if (g_mousecallback == 0 && g_mapNode!=0 && g_mapNode->getTerrainEngine() != 0) {
			osg::ref_ptr<osgEarth::Contrib::MouseCoordsTool> mouseCoordsTool = new osgEarth::Contrib::MouseCoordsTool(g_mapNode);
			g_mousecallback = new MyMouseCallback;
			mouseCoordsTool->addCallback(g_mousecallback);
			viewer.addEventHandler(mouseCoordsTool);
		}
		
		dynamicsWorld->stepSimulation(1.0 / 60.0);
		for (auto it = g_prepareToAddArr.begin(); it != g_prepareToAddArr.end(); it++) {
			root->addChild(*it);
		}
		g_prepareToAddArr.clear();

		g_physicsTerrainGeodeMutex.lock();
		for (auto it = g_physicsTerrainGeodeRemoveArr.begin(); it != g_physicsTerrainGeodeRemoveArr.end(); ++it) {
			root->removeChild(it->get());
		}
		g_physicsTerrainGeodeRemoveArr.clear();
		for (auto it = g_physicsTerrainGeodeInsertArr.begin(); it != g_physicsTerrainGeodeInsertArr.end(); it++) {
			root->addChild(it->get()); 
		}
		g_physicsTerrainGeodeInsertArr.clear();
		g_physicsTerrainGeodeMutex.unlock();

		viewer.frame();
	}


	delete dynamicsWorld;
	delete soler;
	delete broadphase;
	delete dispatcher;
	delete collisionConfiguration;

	return 0;
}